/*
 * @(#)SpringMonitorAopProxy.java   1.0  2022年3月7日
 * 
 * Copyright (c)	2014-2020. All Rights Reserved.	GuangZhou hhmk Technology Company LTD.
 */
package com.swift.monitor.core.proxy;

import java.lang.reflect.Method;
import java.util.Date;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.swift.core.spring.SpringOrder;
import com.swift.monitor.core.config.MonitorConfig;
import com.swift.monitor.core.notice.BeanMonitorNotice;
import com.swift.monitor.core.point.BeanPoint;
import com.swift.util.bean.AopTargetUtils;
import com.swift.util.type.TypeUtil;

/**
 * 拦截所有spring处理器
 * @author zhengjiajin
 * @version 1.0 2022年3月7日
 */
@Aspect
@Component
@Order(SpringOrder.FIRST)
public class SpringMonitorAopProxy {
    
    @Value("${sysId:}")
    private String sysId;
    
    @Autowired
    private BeanMonitorNotice beanMonitorNotice;
   
    @Around("execution(public * com.swift..*.handle..*.*(..)) "
        + "|| @annotation(com.swift.core.monitor.Monitor) "
        + "|| @within(com.swift.core.monitor.Monitor) "
        + "|| this(com.swift.core.monitor.MonitorInterface)")
    private Object filter(ProceedingJoinPoint pjp) throws Throwable {
        if(!MonitorConfig.startMonitor) {
            return pjp.proceed();
        }
        Object target = pjp.getTarget();
        Method currentMethod = AopTargetUtils.getMethod(pjp);
        Class<?>[] para = currentMethod.getParameterTypes();
        BeanPoint point = new BeanPoint();
        point.setThreadId(Thread.currentThread().getId());
        point.setThreadName(Thread.currentThread().getName());
        point.setSysId(sysId);
        point.setClassName(target.getClass().getName());
        point.setMethedName(getMethodName(currentMethod, para));
        point.setStartTime(new Date());
        beanMonitorNotice.notice(point);
        try {
            return pjp.proceed();
        }catch(Throwable ex) {
            point.setEx(ex);
            throw ex;
        }finally {
            point.setEndTime(new Date());
            point.setExecTime(point.getEndTime().getTime()-point.getStartTime().getTime());
            point.setPointTime(new Date());
        }
    }
    
    private String getMethodName(Method currentMethod,Class<?>[] para) {
        StringBuffer sb = new StringBuffer(currentMethod.getName());
        sb.append("(");
        if(TypeUtil.isNotNull(para)) {
            for(int i=0;i<para.length;i++) {
                Class<?> cla = para[i];
                if(i==para.length-1) {
                    sb.append(cla.getSimpleName());
                }else {
                    sb.append(cla.getSimpleName()+",");
                }
            }
        }
        sb.append(")");
        return sb.toString();
    }
}
